import {Message, MessageBox} from 'element-ui'
import {getToken} from '@/utils/auth'

//引入消息发布与订阅框架工具pubsub-js
import pubsub from 'pubsub-js'

import {ping} from '@/api/websocketApi/index'

import store from '@/store'

let webSocket = null;
let isConnect = false; //webSocket的连接状态
let maxReconnectNum = 1000000000; //最大尝试重连次数
let reConnectNum = 0;//重连次数

let websocketUrl = process.env.VUE_APP_WEB_SOCKET;

let globalCallback = function (e) {
  console.log(e)
};//定义外部接收数据的回调函数

//心跳设置
const heartCheck = {
  heartbeatData: "websocket-ping",//心跳包
  timeout: 10 * 1000, //每段时间发送一次心跳包 这里设置为60s
  heartbeat: null, //延时发送消息对象(启动心跳新建这个对象，收到消息后重置对象)
  start: function () {
    this.heartbeat = setInterval(() => {
      if (isConnect) {
        ping(this.heartbeatData);
      } else {
        this.clear();
      }
    }, this.timeout);
  },
  reset: function () {
    clearInterval(this.heartbeat);
    this.start();
  },
  clear: function () {
    clearInterval(this.heartbeat);
  }
};

/**
 * 与服务端建立websocket连接。
 * @param websocketUrl
 * @param callback
 */
export function initWebSocket(websocketUrl, callback) {
  // console.log("openSocket 111 this= ", this) //this= undefined
  console.log("initWebSocket websocketUrl= ", websocketUrl)

  //此callback为在其他地方调用时定义的接收socket数据的函数
  if (callback) {
    if (typeof callback == 'function') {
      globalCallback = callback
    } else {
      throw new Error("callback is not a function")
    }
  }

  if ("WebSocket" in window) {
    // 未前后端分离，所以直接获取本地服务器
    // let socketUrl = window.location.protocol + "//" + document.location.hostname + ":9002/ws/" + 100;
    // // 替换为socket连接
    // socketUrl = socketUrl.replace("http", "ws").replace("https", "wss");
    // 创建socket连接
    // socket = new WebSocket(socketUrl);
    // socket = new WebSocket("ws://localhost:8082/hello/" + token);
    webSocket = new WebSocket(websocketUrl); //创建socket对象
    console.log("initWebSocket webSocket= ", webSocket)

    webSocket.onopen = function () {
      webSocketOpen();
    };

    webSocket.onmessage = onmessage;

    webSocket.onclose = function (e) {
      webSocketOnClose(e)
    };
    webSocket.onerror = function (e) {
      webSocketOnError(e)
    };
  } else {
    console.log("该浏览器不支持websocket!");
    Message({
      message: '该浏览器不支持websocket!',
      type: 'warning'
    });
    return
  }
}

//连接socket建立时触发
function webSocketOpen() {
  console.log("WebSocket连接成功!");

  // axios.get("./testData/navigationInfoTestData.json").then(res => {
  //   console.log("webSocketOpen axios res= ", res)
  //   let navigationInfoTestData = res.data.navigationInfoList;
  //   // console.log("webSocketOpen navigationInfoTestData= ", navigationInfoTestData)
  //
  //   let index = 0;
  //   let length = navigationInfoTestData.length;
  //
  //   setInterval(() => {
  //     pubsub.publish('updateNavigationInfo', navigationInfoTestData[index % length]);
  //     index++;
  //   }, 2000)
  // }).catch(err => {
  //   console.log("webSocketOpen axios err= ", err)
  // })

  // setInterval(() => {
  //   pubsub.publish('updateNavigationInfo', {
  //     hdg: 0,
  //     lon: 114.340154,
  //     lat: 30.4955,
  //     sysBoat: {
  //       boatCode: "05C",
  //       boatId: 14,
  //       boatIdentityId: "4033300833008991",
  //       boatName: "泡泡侠5"
  //     }
  //   });
  // }, 2000)

  //首次握手
  // sendMsg(heartCheck.heartbeatData);
  ping(heartCheck.heartbeatData);
  isConnect = true;
  heartCheck.start();
  reConnectNum = 0;
}

/**
 * 发送消息。支持文本及二进制消息。
 * @param msgObj
 */
export function sendMsg(msgObj) {
  if (!msgObj || !webSocket) return;
  if (webSocket.readyState !== WebSocket.OPEN) {
    console.log("webSocket未连接，消息发送失败!");
    return;
  }
  if (msgObj instanceof Blob) {
    sendBinaryMsg(msgObj)
  } else {
    sendTextMsg(msgObj)
  }
}

/**
 * 发送文本消息。
 * @param msg
 */
function sendTextMsg(msgObj) {
  console.log("sendTextMsg execute. msgObj: ", msgObj)
  webSocket.send(JSON.stringify({
    // token: getToken(), //此处没必要带token，客户端在首次建立连接时带上token进行鉴权即可。
    code: msgObj.code || 200,
    // token: getToken(), //发起连接时需带上token，后续发送消息时就无需再带token
    msg: msgObj.msg || '',
    timestamp: new Date().getTime(),
    data: msgObj.data || {}
  }))
}

/**
 * 发送二进制数据。
 * @param blobMsg
 */
function sendBinaryMsg(blobMsg) {
  console.log("sendBinaryMsg execute. blobMsg: ", blobMsg)
  webSocket.send(blobMsg);
}

/**
 * 关闭websocket连接。
 * @param code
 * @param reason
 */
export function closeSocket(code, reason) {
  console.log("closeSocket: ", code, reason)
  if (!webSocket) return;
  if (webSocket.readyState !== WebSocket.OPEN) return;

  sendMsg({
    code: code || 1000,
    msg: reason || '',
  })

  webSocket.close(code, reason);
  heartCheck.clear();
  isConnect = false; //断开后修改标识
}

/**
 * 获取websocket的登录状态
 * @returns {boolean}
 */
export function isWebSocketConnected() {
  return isConnect;
}

//获得消息事件
function onmessage(msg) {
  console.log("onmessage msg: ", msg)
  const receivedData = JSON.parse(msg.data);
  console.log("接收到服务端发送过来的消息, receivedData：", receivedData);
  // console.log("this.webSocket.onmessage that= ", that)
  // let jsonData = JSON.parse(msg.data);
  // 赋值消息到文本域（接到消息了自行决定如何操作）
  // $("#replyContent").append("用户『" + jsonData.username + "』说：" + jsonData.question + "\n");
  // that.sendMsg("这是来自客户端的消息" + msg);
  let code = receivedData.code;
  let data = receivedData.data;
  if (!code || !data) return
  switch (code) {
    case 4002:
      //通知景区运营状态被更新的信息
      store.dispatch("ChangeOperationStatus", {
        operationStatus: data.operationStatus
      })
      break;
    case 4006:
      //接收到泡泡豚实时状态被更新的信息
      pubsub.publish("updateBoatRealtimeStatusInfo", data);
      break;
    case 4010:
      //接收到泡泡豚船只电池状态被更新的信息
      pubsub.publish("updateBoatBatteryStatusInfo", data);
      break;
    case 4011:
      //接收到泡泡豚船只运营状态被更新的信息
      pubsub.publish("updateBoatOperationStatusInfo", data);
      break;
    case 4012:
      //接收到景区运营动态被更新的信息
      pubsub.publish("updateScenicOperationDynamicInfo", data);
      break;
    case 4014:
      //接收到景区历史累计总收入被更新的信息
      pubsub.publish("updateScenicAccumulatedTotalIncome", data);
      break;
    case 4015:
      //接收到景区船只报警信息被更新的信息
      pubsub.publish("updateScenicBoatAlarmInfo", data);
      break;
  }
};

//socket关闭时触发 (一般是被动断开时才触发)
function webSocketOnClose(closeEvent) {
  let code = closeEvent.code;
  heartCheck.clear();
  isConnect = false; //断开后修改标识
  console.log(closeEvent)
  console.log('webSocket已经关闭 (code：' + code + ', reason: ' + closeEvent.reason + ')')
  // 客户端接收到的关闭事件的状态码为1006的可能场景：
  // 1，服务器主动关机；
  // 2，服务器出故障，如宕机等；
  // 3，服务器在ws连接还未建立完成(比如还在http请求阶段)时调用ctx.close()或channel.close()方法主动关闭连接；
  if (code === 1006) { //被动断开(如服务器出故障，宕机等)，重新连接
    if (reConnectNum < maxReconnectNum) {
      let token = getToken();
      if (!token || token === "") return;

      let websocketUrl = process.env.VUE_APP_WEB_SOCKET + '?token=' + token;
      //每间隔3秒尝试重连一次。
      var timer = setTimeout(() => {
        if (!isConnect) {
          initWebSocket(websocketUrl);
          ++reConnectNum;
        } else {
          console.log("websocket已连接，关闭重连定时器。")
          clearTimeout(timer);
        }
      }, 3000);
    } else {
      Message(
        {
          message: 'websocket连接不上，请刷新页面或联系开发人员!',
          type: 'warning'
        }
      );
    }
  } else if (code === 4001) { //服务器在校验token时发现token无效或已过期,服务器主动断开当前websocket连接.
    store.dispatch('LogOut').then(() => {
      // Message.error("登录状态已过期，请重新登录！")
      MessageBox.confirm("登录状态已过期，请选择是否重新登录？", "系统提示", {
        confirmButtonText: '重新登录',
        cancelButtonText: '取消',
        type: "warning",
        closeOnClickModal: false,
        closeOnPressEscape: false
      }).then(() => {
        location.href = '/index';
      }).catch(() => {
      })
    })
  }
}

//连接发生错误的回调方法
function webSocketOnError(e) {
  heartCheck.clear();
  isConnect = false; //断开后修改标识
  console.log("WebSocket连接发生错误:");
  // console.log(e);
}


